/**
 * @Author       : Mo 2427995270@qq.com
 * @Date         : 2025-06-03 23:06:47
 * @LastEditTime : 2025-07-16 21:24:07
 * @FilePath     : \STM32F103-DEMO\hal_driver\ll_spi.c
 * @Description  : spi低层驱动
 * @Version      : V1.0
 * @History      :
 * @Note         : 暂不支持单线模式和中断
 */
/***************************************Includes***********************************/
#include "ll_spi.h"
#include "hal_delay.h"

#if defined(GD32F407)
#include "gd32f4xx.h"
#elif defined(GD32F10X_HD)
#include "gd32f10x.h"
#elif defined(STM32F10X_HD)
#include "stm32f10x.h"
#elif defined(STM32F40_41xxx)
#include "stm32f4xx.h"
#elif defined(PY32F071xB)
#include "py32f0xx.h"
#else
#error "No device selected"
#endif

/************************************Private Macros********************************/
// #define


/**********************************Private Statement*******************************/

static int GD32F407_spi_init(spi_ll_t *slt, uint32_t clk_freq, spi_ll_config_t *config);
static int stm32_spi_init(spi_ll_t *slt, uint32_t clk_freq, spi_ll_config_t *config);
static int PY32F071xB_spi_init(spi_ll_t *slt, uint32_t clk_freq, spi_ll_config_t *config);

/***********************************Public Variables*******************************/



/**********************************Private Variables*******************************/



/**********************************Public Functions********************************/

/**
 * @brief spi初始化
 * @param  slt
 * @param  clk_freq         Spi频率
 * @param  config           Spi配置
 * @return int 0成功 -1失败
 * @note null
 */
int spi_ll_init(spi_ll_t *slt, uint32_t clk_freq, spi_ll_config_t *config) {

#if defined(GD32F407) || defined(GD32F10X_HD)
    return GD32F407_spi_init(slt, clk_freq, config);
#elif defined(STM32F40_41xxx) || defined(STM32F10X_HD)
    return stm32_spi_init(slt, clk_freq, config);
#elif defined(PY32F071xB)
    return PY32F071xB_spi_init(slt, clk_freq, config);
#endif

    return -1;
}
/**
 * @brief spi传输和接收
 * @param  slt
 * @param  tx_data          发送的数据
 * @param  rx_data          接收的数据
 * @param  len              数据长度 1个长度对应8bit的一字节 对应16Bit的二个字节
 * @return int 0成功 -1失败
 * @note null
 */
int spi_ll_transmit_receive(spi_ll_t *slt, void *tx_data, void *rx_data, uint32_t len) {
#define DELAY_TIME 10
    if (slt->datasize == SPI_LL_DATASIZE_16BIT) {
        uint16_t *tx = tx_data;
        uint16_t *rx = rx_data;
        for (uint32_t i = 0; i < len; i++) {
            uint32_t timeout = 5 * (1000 / DELAY_TIME); // 5ms
#if defined(GD32F407) || defined(GD32F10X_HD)
            while (RESET == spi_i2s_flag_get(slt->spix, SPI_FLAG_TBE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            timeout = 5 * (1000 / DELAY_TIME);
            spi_i2s_data_transmit(slt->spix, tx[i]);
            while (RESET == spi_i2s_flag_get(slt->spix, SPI_FLAG_RBNE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            rx[i] = spi_i2s_data_receive(slt->spix);
#elif defined(STM32F40_41xxx) || defined(STM32F10X_HD)
            while (RESET == SPI_I2S_GetFlagStatus((void *)slt->spix, SPI_I2S_FLAG_TXE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            timeout = 5 * (1000 / DELAY_TIME);
            SPI_I2S_SendData((void *)slt->spix, tx[i]);
            while (RESET == SPI_I2S_GetFlagStatus((void *)slt->spix, SPI_I2S_FLAG_RXNE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            rx[i] = SPI_I2S_ReceiveData((void *)slt->spix);
#elif defined(PY32F071xB)
            while (!__HAL_SPI_GET_FLAG((SPI_HandleTypeDef *)slt->spix, SPI_FLAG_TXE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            ((SPI_HandleTypeDef *)slt->spix)->Instance->DR = tx[i];
            while (!__HAL_SPI_GET_FLAG((SPI_HandleTypeDef *)slt->spix, SPI_FLAG_RXNE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            rx[i] = ((SPI_HandleTypeDef *)slt->spix)->Instance->DR;
#endif
        } // for
    } else {
        uint8_t *tx = tx_data;
        uint8_t *rx = rx_data;
        for (uint32_t i = 0; i < len; i++) {
            uint32_t timeout = 5 * (1000 / DELAY_TIME); // 5ms
#if defined(GD32F407) || defined(GD32F10X_HD)
            while (RESET == spi_i2s_flag_get(slt->spix, SPI_FLAG_TBE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            timeout = 5 * (1000 / DELAY_TIME);
            spi_i2s_data_transmit(slt->spix, tx[i]);
            while (RESET == spi_i2s_flag_get(slt->spix, SPI_FLAG_RBNE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            rx[i] = spi_i2s_data_receive(slt->spix);
#elif defined(STM32F40_41xxx) || defined(STM32F10X_HD)
            while (RESET == SPI_I2S_GetFlagStatus((void *)slt->spix, SPI_I2S_FLAG_TXE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            timeout = 5 * (1000 / DELAY_TIME);
            SPI_I2S_SendData((void *)slt->spix, tx[i]);
            while (RESET == SPI_I2S_GetFlagStatus((void *)slt->spix, SPI_I2S_FLAG_RXNE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            rx[i] = SPI_I2S_ReceiveData((void *)slt->spix);
#elif defined(PY32F071xB)
            while (!__HAL_SPI_GET_FLAG((SPI_HandleTypeDef *)slt->spix, SPI_FLAG_TXE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            ((SPI_HandleTypeDef *)slt->spix)->Instance->DR = tx[i];
            while (!__HAL_SPI_GET_FLAG((SPI_HandleTypeDef *)slt->spix, SPI_FLAG_RXNE)) {
                delay_us_not_os(DELAY_TIME);
                timeout--;
                if (timeout == 0) {
                    goto __exit;
                }
            }
            rx[i] = ((SPI_HandleTypeDef *)slt->spix)->Instance->DR;
#endif
        } // for
    }
    return 0;
__exit:
    return -1;
}

/**
 * @brief spi传输和接收一个字节
 * @param  slt
 * @param  tx_data          发送的数据
 * @return int 接收的数据
 * @note null
 */
int spi_ll_transmit_receive_byte(spi_ll_t *slt, uint16_t tx_data) {
#define DELAY_TIME 10
    uint16_t ret = 0;
    if (slt->datasize == SPI_LL_DATASIZE_16BIT) {
        uint32_t timeout = 5 * (1000 / DELAY_TIME); // 5ms
#if defined(GD32F407) || defined(GD32F10X_HD)
        while (RESET == spi_i2s_flag_get(slt->spix, SPI_FLAG_TBE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        spi_i2s_data_transmit(slt->spix, tx_data);
        timeout = 5 * (1000 / DELAY_TIME);
        while (RESET == spi_i2s_flag_get(slt->spix, SPI_FLAG_RBNE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        ret = spi_i2s_data_receive(slt->spix);
#elif defined(STM32F40_41xxx) || defined(STM32F10X_HD)
        while (RESET == SPI_I2S_GetFlagStatus((void *)slt->spix, SPI_I2S_FLAG_TXE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        timeout = 5 * (1000 / DELAY_TIME);
        SPI_I2S_SendData((void *)slt->spix, tx_data);
        while (RESET == SPI_I2S_GetFlagStatus((void *)slt->spix, SPI_I2S_FLAG_RXNE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        ret = SPI_I2S_ReceiveData((void *)slt->spix);
#elif defined(PY32F071xB)
        while (!__HAL_SPI_GET_FLAG((SPI_HandleTypeDef *)slt->spix, SPI_FLAG_TXE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        ((SPI_HandleTypeDef *)slt->spix)->Instance->DR = tx_data;
        while (!__HAL_SPI_GET_FLAG((SPI_HandleTypeDef *)slt->spix, SPI_FLAG_RXNE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        ret = ((SPI_HandleTypeDef *)slt->spix)->Instance->DR;
#endif
    } else {
        uint32_t timeout = 5 * (1000 / DELAY_TIME); // 5ms
#if defined(GD32F407) || defined(GD32F10X_HD)
        while (RESET == spi_i2s_flag_get(slt->spix, SPI_FLAG_TBE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        spi_i2s_data_transmit(slt->spix, tx_data);
        timeout = 5 * (1000 / DELAY_TIME);
        while (RESET == spi_i2s_flag_get(slt->spix, SPI_FLAG_RBNE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        ret = spi_i2s_data_receive(slt->spix);
#elif defined(STM32F40_41xxx) || defined(STM32F10X_HD)
        while (RESET == SPI_I2S_GetFlagStatus((void *)slt->spix, SPI_I2S_FLAG_TXE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        timeout = 5 * (1000 / DELAY_TIME);
        SPI_I2S_SendData((void *)slt->spix, tx_data);
        while (RESET == SPI_I2S_GetFlagStatus((void *)slt->spix, SPI_I2S_FLAG_RXNE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        ret = SPI_I2S_ReceiveData((void *)slt->spix);
#elif defined(PY32F071xB)
        while (!__HAL_SPI_GET_FLAG((SPI_HandleTypeDef *)slt->spix, SPI_FLAG_TXE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        ((SPI_HandleTypeDef *)slt->spix)->Instance->DR = tx_data & 0xff;
        while (!__HAL_SPI_GET_FLAG((SPI_HandleTypeDef *)slt->spix, SPI_FLAG_RXNE)) {
            delay_us_not_os(DELAY_TIME);
            timeout--;
            if (timeout == 0) {
                goto __exit;
            }
        }
        ret = ((SPI_HandleTypeDef *)slt->spix)->Instance->DR;
#endif
    }
    return ret;
__exit:
    return -1;
}
/**
 * @brief spi片选使能
 * @param  slt
 * @param  nen              0使能 1禁用
 * @return int 0成功 -1失败
 * @note null
 */
int spi_ll_chip_select_en(spi_ll_t *slt, int nen) {
    if (slt->port_nss) {
        gpio_ll_set_output(&slt->gpio_nss, nen ? 1 : 0);
        return 0;
    } else {
        return -1;
    }
}

/**********************************Private Functions*******************************/

static int GD32F407_spi_init(spi_ll_t *slt, uint32_t clk_freq, spi_ll_config_t *config) {
    if ((config->direction == SPI_LL_DIRECTION_1LINS_RX) || (config->direction == SPI_LL_DIRECTION_1LINS_TX)) {
        return -1;
    }
    // clang-format off
    slt->port_sck = config->port_sck;
    slt->port_miso = config->port_miso;
    slt->port_mosi = config->port_mosi;
    slt->port_nss = config->port_nss;
    slt->pin_sck = config->pin_sck;
    slt->pin_miso = config->pin_miso;
    slt->pin_mosi = config->pin_mosi;
    slt->pin_nss = config->pin_nss;
    slt->spix = config->spix;
    slt->datasize = config->datasize;
    slt->spi_ll_direction = config->direction;
    slt->cfg_interrupt_priority = config->cfg_interrupt_priority;
#if defined(GD32F407)
    uint32_t af_sck, af_miso, af_mosi;
    switch (slt->spix) {
    case SPI0:
        af_sck = GPIO_AF_5;
        af_miso = GPIO_AF_5;
        af_mosi = GPIO_AF_5;
        break;
    case SPI1:
        af_sck = GPIO_AF_5;
        af_miso = GPIO_AF_5;
        af_mosi = GPIO_AF_5;
        if ((slt->port_mosi == GPIOC) && (slt->pin_mosi == GPIO_PIN_1)) {
            af_mosi = GPIO_AF_7;
        }
        break;
    case SPI2:
        af_sck = GPIO_AF_6;
        af_miso = GPIO_AF_6;
        if (slt->port_mosi == GPIOB) {
            if ((slt->pin_mosi == GPIO_PIN_0) || (slt->pin_mosi == GPIO_PIN_2)) {
                af_mosi = GPIO_AF_7;
            } else {
                af_mosi = GPIO_AF_6;
            }
        } else if (slt->port_mosi == GPIOC) {
            if (slt->pin_mosi == GPIO_PIN_1) {
                af_mosi = GPIO_AF_5;
            } else {
                af_mosi = GPIO_AF_6;
            }
        } else if (slt->port_mosi == GPIOD) {
            if (slt->pin_mosi == GPIO_PIN_0) {
                af_mosi =GPIO_AF_6;
            } else {
                af_mosi = GPIO_AF_5;
            }
        } else {
            return -1;
        }
        break;
    default: return -1;
    }
    gpio_ll_t gpio_cfg;
    gpio_ll_init(&gpio_cfg, slt->port_sck, slt->pin_sck, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_VERY_HIGH, af_sck);
    gpio_ll_init(&gpio_cfg, slt->port_miso, slt->pin_miso, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_VERY_HIGH, af_miso);
    if (slt->spi_ll_direction == SPI_LL_DIRECTION_2LINS_FULL_DUPLEX) {
        gpio_ll_init(&gpio_cfg, slt->port_mosi, slt->pin_mosi, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_VERY_HIGH, af_mosi);
    }
    if (slt->port_nss) {
        if (config->mode == SPI_LL_MODE_MASTER) {
            gpio_ll_init(&slt->gpio_nss, slt->port_nss, slt->pin_nss, GPIO_LL_MODE_OUTPUT, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_MEDIUM, 0);
        } else {
            gpio_ll_init(&slt->gpio_nss, slt->port_nss, slt->pin_nss, GPIO_LL_MODE_INPUT, GPIO_LL_OTYPE_OD, GPIO_LL_PULL_DOWN, GPIO_LL_SPEED_MEDIUM, 0);
        }
    }
#endif
#if defined(GD32F10X_HD)
    if ((slt->port_sck == GPIOC) && (slt->pin_sck == GPIO_PIN_10) && (slt->spix == SPI2)) {
        gpio_pin_remap_config(GPIO_SPI2_REMAP, ENABLE);
    }
    if ((slt->port_miso == GPIOC) && (slt->pin_miso == GPIO_PIN_11) && (slt->spix == SPI2)) {
        gpio_pin_remap_config(GPIO_SPI2_REMAP, ENABLE);
    }
    if ((slt->port_mosi == GPIOC) && (slt->pin_mosi== GPIO_PIN_12) && (slt->spix == SPI2)) {
        gpio_pin_remap_config(GPIO_SPI2_REMAP, ENABLE);
    }
    if ((slt->port_sck == GPIOB) && (slt->pin_sck == GPIO_PIN_3) && (slt->spix == SPI0)) {
        gpio_pin_remap_config(GPIO_SPI0_REMAP, ENABLE);
    }
    if ((slt->port_miso == GPIOB) && (slt->pin_miso == GPIO_PIN_4) && (slt->spix == SPI0)) {
        gpio_pin_remap_config(GPIO_SPI0_REMAP, ENABLE);
    }
    if ((slt->port_mosi == GPIOB) && (slt->pin_mosi== GPIO_PIN_5) && (slt->spix == SPI0)) {
        gpio_pin_remap_config(GPIO_SPI0_REMAP, ENABLE);
    }

    gpio_ll_t gpio_cfg;
    gpio_ll_init(&gpio_cfg, slt->port_sck, slt->pin_sck, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_VERY_HIGH, 0);
    gpio_ll_init(&gpio_cfg, slt->port_miso, slt->pin_miso, GPIO_LL_MODE_INPUT, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_VERY_HIGH, 0);
    if (slt->spi_ll_direction == SPI_LL_DIRECTION_2LINS_FULL_DUPLEX) {
        gpio_ll_init(&gpio_cfg, slt->port_mosi, slt->pin_mosi, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_VERY_HIGH, 0);
    }
    if (slt->port_nss) {
        if (config->mode == SPI_LL_MODE_MASTER) {
            gpio_ll_init(&slt->gpio_nss, slt->port_nss, slt->pin_nss, GPIO_LL_MODE_OUTPUT, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_MEDIUM, 0);
        } else {
            gpio_ll_init(&slt->gpio_nss, slt->port_nss, slt->pin_nss, GPIO_LL_MODE_INPUT, GPIO_LL_OTYPE_OD, GPIO_LL_PULL_DOWN, GPIO_LL_SPEED_MEDIUM, 0);
        }
    }
#endif
#if defined(GD32F407) || defined(GD32F10X_HD)
    spi_parameter_struct spi_cfg;
    switch (config->direction) {
    case SPI_LL_DIRECTION_2LINS_FULL_DUPLEX: spi_cfg.trans_mode = SPI_TRANSMODE_FULLDUPLEX; break;
    case SPI_LL_DIRECTION_2LINS_RXONLY: spi_cfg.trans_mode = SPI_TRANSMODE_RECEIVEONLY; break;
    case SPI_LL_DIRECTION_1LINS_RX: spi_cfg.trans_mode = SPI_TRANSMODE_BDRECEIVE; break;
    case SPI_LL_DIRECTION_1LINS_TX: spi_cfg.trans_mode = SPI_TRANSMODE_BDTRANSMIT; break;
    default: return -1;
    }
    switch (config->mode) {
    case SPI_LL_MODE_MASTER: spi_cfg.device_mode = SPI_MASTER; break;
    case SPI_LL_MODE_SLAVE: spi_cfg.device_mode = SPI_SLAVE; break;
    default: return -1;
    }
    switch (config->datasize) {
    case SPI_LL_DATASIZE_8BIT: spi_cfg.frame_size = SPI_FRAMESIZE_8BIT; break;
    case SPI_LL_DATASIZE_16BIT: spi_cfg.frame_size = SPI_FRAMESIZE_16BIT; break;
    default: return -1;
    }
    switch (config->clk_polarity) {
    case SPI_LL_CLK_POLARITY_LOW: 
        switch (config->phase) {
        case SPI_LL_PHASE_1EDGE: spi_cfg.clock_polarity_phase = SPI_CK_PL_LOW_PH_1EDGE; break;
        case SPI_LL_PHASE_2EDGE: spi_cfg.clock_polarity_phase = SPI_CK_PL_LOW_PH_2EDGE; break;
        default: return -1;
        }
        break;
    case SPI_LL_CLK_POLARITY_HIGH:
        switch (config->phase) {
        case SPI_LL_PHASE_1EDGE: spi_cfg.clock_polarity_phase = SPI_CK_PL_HIGH_PH_1EDGE; break;
        case SPI_LL_PHASE_2EDGE: spi_cfg.clock_polarity_phase = SPI_CK_PL_HIGH_PH_2EDGE; break;
        default: return -1;
        }
        break;
    default: return -1;
    }
    spi_cfg.nss = SPI_NSS_SOFT;
    uint32_t apbsclk;
    switch (slt->spix) {
    case SPI0: apbsclk = rcu_clock_freq_get(CK_APB2); break;
    case SPI1:
    case SPI2: apbsclk = rcu_clock_freq_get(CK_APB1); break;
    default: return -1;
    }
    float psc = (float)apbsclk / clk_freq;
    if (psc < 2) {
        spi_cfg.prescale = SPI_PSC_2;
    } else if(psc < 4) {
        spi_cfg.prescale = SPI_PSC_4;
    } else if(psc < 8) {
        spi_cfg.prescale = SPI_PSC_8;
    } else if(psc < 16) {
        spi_cfg.prescale = SPI_PSC_16;
    } else if(psc < 32) {
        spi_cfg.prescale = SPI_PSC_32;
    } else if(psc < 64) {
        spi_cfg.prescale = SPI_PSC_64;
    } else if(psc < 128) {
        spi_cfg.prescale = SPI_PSC_128;
    } else {
        spi_cfg.prescale = SPI_PSC_256;
    }
    switch (config->first_bit) {
    case SPI_LL_FIRST_BIT_MSB: spi_cfg.endian = SPI_ENDIAN_MSB; break;
    case SPI_LL_FIRST_BIT_LSB: spi_cfg.endian = SPI_ENDIAN_LSB; break;
    default: return -1;
    }
    switch (slt->spix) {
    case SPI0: rcu_periph_clock_enable(RCU_SPI0); break;
    case SPI1: rcu_periph_clock_enable(RCU_SPI1); break;
    case SPI2: rcu_periph_clock_enable(RCU_SPI2); break;
    default: return -1;
    }
    spi_i2s_deinit(slt->spix);
    spi_init(slt->spix, &spi_cfg);
    if (config->crc_polynomial) {
        spi_crc_polynomial_set(slt->spix, config->cfg_interrupt_priority);
        spi_crc_on(slt->spix);
    }
    spi_enable(slt->spix);
    return 0;
#endif
    // clang-format on
    return -1;
}

static int stm32_spi_init(spi_ll_t *slt, uint32_t clk_freq, spi_ll_config_t *config) {
    if ((config->direction == SPI_LL_DIRECTION_1LINS_RX) || (config->direction == SPI_LL_DIRECTION_1LINS_TX)) {
        return -1;
    }
    // clang-format off
    slt->port_sck = config->port_sck;
    slt->port_miso = config->port_miso;
    slt->port_mosi = config->port_mosi;
    slt->port_nss = config->port_nss;
    slt->pin_sck = config->pin_sck;
    slt->pin_miso = config->pin_miso;
    slt->pin_mosi = config->pin_mosi;
    slt->pin_nss = config->pin_nss;
    slt->spix = config->spix;
    slt->datasize = config->datasize;
    slt->spi_ll_direction = config->direction;
    slt->cfg_interrupt_priority = config->cfg_interrupt_priority;
#if defined(STM32F10X_HD)
    gpio_ll_t gpio_cfg;
    if (config->mode == SPI_LL_MODE_MASTER) {
        gpio_ll_init(&gpio_cfg, slt->port_sck, slt->pin_sck, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_HIGH, 0);
        gpio_ll_init(&gpio_cfg, slt->port_mosi, slt->pin_mosi, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_HIGH, 0);
    } else {
        // todo 暂不支持从机
        return -1;
    }
    gpio_ll_init(&gpio_cfg, slt->port_miso, slt->pin_miso, GPIO_LL_MODE_INPUT, GPIO_LL_OTYPE_OD, GPIO_LL_PULL_NO, GPIO_LL_SPEED_HIGH, 0);
    if (slt->port_nss) {
        if (config->mode == SPI_LL_MODE_MASTER) {
            gpio_ll_init(&slt->gpio_nss, slt->port_nss, slt->pin_nss, GPIO_LL_MODE_OUTPUT, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_MEDIUM, 0);
        } else {
            gpio_ll_init(&slt->gpio_nss, slt->port_nss, slt->pin_nss, GPIO_LL_MODE_INPUT, GPIO_LL_OTYPE_OD, GPIO_LL_PULL_DOWN, GPIO_LL_SPEED_MEDIUM, 0);
        }
    }
#endif

#if defined(STM32F40_41xxx)
#endif

#if defined(STM32F40_41xxx) || defined(STM32F10X_HD)
    SPI_InitTypeDef spi_cfg;
    switch (config->direction) {
    case SPI_LL_DIRECTION_2LINS_FULL_DUPLEX: spi_cfg.SPI_Direction = SPI_Direction_2Lines_FullDuplex; break;
    case SPI_LL_DIRECTION_2LINS_RXONLY: spi_cfg.SPI_Direction = SPI_Direction_2Lines_RxOnly; break;
    case SPI_LL_DIRECTION_1LINS_RX: spi_cfg.SPI_Direction = SPI_Direction_1Line_Rx; break;
    case SPI_LL_DIRECTION_1LINS_TX: spi_cfg.SPI_Direction = SPI_Direction_1Line_Tx; break;
    default: return -1;
    }
    switch (config->mode) {
    case SPI_LL_MODE_MASTER: spi_cfg.SPI_Mode = SPI_Mode_Master; break;
    case SPI_LL_MODE_SLAVE: spi_cfg.SPI_Mode = SPI_Mode_Slave; break;
    default: return -1;
    }
    switch (config->datasize) {
    case SPI_LL_DATASIZE_8BIT: spi_cfg.SPI_DataSize = SPI_DataSize_8b; break;
    case SPI_LL_DATASIZE_16BIT: spi_cfg.SPI_DataSize = SPI_DataSize_16b; break;
    default: return -1;
    }
    switch (config->clk_polarity) {
    case SPI_LL_CLK_POLARITY_LOW: spi_cfg.SPI_CPOL = SPI_CPOL_Low; break;
    case SPI_LL_CLK_POLARITY_HIGH: spi_cfg.SPI_CPOL = SPI_CPOL_High; break;
    default: return -1;
    }
    switch (config->phase) {
    case SPI_LL_PHASE_1EDGE: spi_cfg.SPI_CPHA = SPI_CPHA_1Edge; break;
    case SPI_LL_PHASE_2EDGE: spi_cfg.SPI_CPHA = SPI_CPHA_2Edge; break;
    default: return -1;
    }
    spi_cfg.SPI_NSS = SPI_NSS_Soft;
    RCC_ClocksTypeDef clk;
    RCC_GetClocksFreq(&clk);
    uint32_t apbsclk;
    switch (slt->spix) {
    case (uint32_t)SPI1: apbsclk = clk.PCLK2_Frequency; break;
    case (uint32_t)SPI2:
    case (uint32_t)SPI3: apbsclk = clk.PCLK1_Frequency; break;
    default: return -1;
    }
    float psc = (float)apbsclk / clk_freq;
    if (psc < 2) {
        spi_cfg.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
    } else if(psc < 4) {
        spi_cfg.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
    } else if(psc < 8) {
        spi_cfg.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
    } else if(psc < 16) {
        spi_cfg.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_16;
    } else if(psc < 32) {
        spi_cfg.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_32;
    } else if(psc < 64) {
        spi_cfg.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64;
    } else if(psc < 128) {
        spi_cfg.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_128;
    } else {
        spi_cfg.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
    }
    switch (config->first_bit) {
    case SPI_LL_FIRST_BIT_MSB: spi_cfg.SPI_FirstBit = SPI_FirstBit_MSB; break;
    case SPI_LL_FIRST_BIT_LSB: spi_cfg.SPI_FirstBit = SPI_FirstBit_LSB; break;
    default: return -1;
    }
    switch (slt->spix) {
    case (uint32_t)SPI1: RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1, ENABLE); break;
    case (uint32_t)SPI2: RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); break;
    case (uint32_t)SPI3: RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI3, ENABLE); break;
    default: return -1;
    }
    spi_cfg.SPI_CRCPolynomial = config->crc_polynomial;
    SPI_Init((void *)slt->spix, &spi_cfg);
    SPI_Cmd((void *)slt->spix, ENABLE);
    return 0;
#endif
    // clang-format on
    return -1;
}

static int PY32F071xB_spi_init(spi_ll_t *slt, uint32_t clk_freq, spi_ll_config_t *config) {
#if defined(PY32F071xB)
    // clang-format off
    if((config->direction == SPI_LL_DIRECTION_1LINS_RX) || (config->direction == SPI_LL_DIRECTION_1LINS_TX)) {
        return -1;
    }
    SPI_HandleTypeDef *spi_handle = (void *)slt->spix;
    spi_handle->Instance = (void *)config->spix;
    slt->port_sck = config->port_sck;
    slt->port_miso = config->port_miso;
    slt->port_mosi = config->port_mosi;
    slt->port_nss = config->port_nss;
    slt->pin_sck = config->pin_sck;
    slt->pin_miso = config->pin_miso;
    slt->pin_mosi = config->pin_mosi;
    slt->pin_nss = config->pin_nss;
    slt->datasize = config->datasize;
    slt->spi_ll_direction = config->direction;
    slt->cfg_interrupt_priority = config->cfg_interrupt_priority;

    uint32_t af_sck, af_miso, af_mosi;
    switch ((uint32_t)spi_handle->Instance) {
    case (uint32_t)SPI1:
        switch (slt->port_sck) {
        case (uint32_t)GPIOA: 
            switch (slt->pin_sck) {
            case GPIO_PIN_1: af_sck = GPIO_AF8_SPI1; break;
            case GPIO_PIN_5: af_sck = GPIO_AF0_SPI1; break;
            default: return -1;
            }
            break;
        case (uint32_t)GPIOB: 
            if (slt->pin_sck == GPIO_PIN_3) {
                af_sck = GPIO_AF0_SPI1;
            } else {
                return -1;
            }
            break;
        case (uint32_t)GPIOC:
            if (slt->pin_sck == GPIO_PIN_13) {
                af_sck = GPIO_AF8_SPI1;
            } else {
                return -1;
            }
            break;
        default: return -1;
        }
        break;
    case (uint32_t)SPI2:
        switch (slt->port_sck) {
        case (uint32_t)GPIOA:
            if (slt->pin_sck == GPIO_PIN_0) {
                af_sck = GPIO_AF8_SPI2;
            } else {
                return -1;
            }
            break;
        case (uint32_t)GPIOB:
            switch (slt->pin_sck) {
            case GPIO_PIN_8: af_sck = GPIO_AF8_SPI2; break;
            case GPIO_PIN_10: af_sck = GPIO_AF5_SPI2; break;
            case GPIO_PIN_13: af_sck = GPIO_AF0_SPI2; break;
            default: return -1;
            }
            break;
        case (uint32_t)GPIOC:
            if (slt->pin_sck == GPIO_PIN_6) {
                af_sck = GPIO_AF8_SPI2;
            } else {
                return -1;
            }
            break;
        default: return -1;
        }
        break;
    default: return -1;
    }
    
    switch ((uint32_t)spi_handle->Instance) {
    case (uint32_t)SPI1:
        switch (slt->port_miso) {
        case (uint32_t)GPIOA:
            switch (slt->pin_miso) {
            case GPIO_PIN_6: af_miso = GPIO_AF0_SPI1; break;
            case GPIO_PIN_11: af_miso = GPIO_AF8_SPI1; break;
            default: return -1;
            }
            break;
        case (uint32_t)GPIOB:
            if (slt->pin_miso == GPIO_PIN_4) {
                af_miso = GPIO_AF0_SPI1;
            } else {
                return -1;
            }
            break;
        case (uint32_t)GPIOC:
            if (slt->pin_miso == GPIO_PIN_0) {
                af_miso = GPIO_AF8_SPI1;
            } else {
                return -1;
            }
            break;
        default: return -1;
        }
        break;
    case (uint32_t)SPI2:
        switch (slt->port_miso) {
        case (uint32_t)GPIOA:
            switch (slt->pin_miso) {
            case GPIO_PIN_2: af_miso = GPIO_AF9_SPI2; break;
            case GPIO_PIN_9: af_miso = GPIO_AF8_SPI2; break;
            default: return -1;
            }
            break;
        case (uint32_t)GPIOB:
            switch (slt->pin_miso) {
            case GPIO_PIN_2: 
            case GPIO_PIN_6: af_miso = GPIO_AF8_SPI2; break;
            case GPIO_PIN_14: af_miso = GPIO_AF0_SPI2; break;
            default: return -1;
            }
            break;
        case (uint32_t)GPIOC:
            switch (slt->pin_miso) {
            case GPIO_PIN_2: af_miso = GPIO_AF1_SPI2; break;
            case GPIO_PIN_7: af_miso = GPIO_AF8_SPI2; break;
            default: return -1;
            }
            break;
        default: return -1;
        }
        break;
    default: return -1;
    }
    if (config->direction == SPI_LL_DIRECTION_2LINS_FULL_DUPLEX)
    switch ((uint32_t)spi_handle->Instance) {
    case (uint32_t)SPI1:
        switch (slt->port_mosi) {
        case (uint32_t)GPIOA:
            switch (slt->pin_miso) {
            case GPIO_PIN_7: af_mosi = GPIO_AF0_SPI1; break;
            case GPIO_PIN_2: 
            case GPIO_PIN_12: af_mosi = GPIO_AF8_SPI1; break;
            default: return -1;
            }
            break;
        case (uint32_t)GPIOB:
            if (slt->pin_miso == GPIO_PIN_5) {
                af_mosi = GPIO_AF0_SPI1;
            } else {
                return -1;
            }
            break;
        case (uint32_t)GPIOC:
            switch (slt->pin_mosi) {
            case GPIO_PIN_1: 
            case GPIO_PIN_5: af_mosi = GPIO_AF8_SPI1; break;
            default: return -1;
            }
            break;
        default: return -1;
        }
        break;
    case (uint32_t)SPI2:
        switch (slt->port_mosi) {
        case (uint32_t)GPIOA:
            switch (slt->pin_mosi) {
            case GPIO_PIN_1: af_mosi = GPIO_AF9_SPI2; break;
            case GPIO_PIN_4: 
            case GPIO_PIN_10: af_mosi = GPIO_AF8_SPI2; break;
            default: return -1;
            }
            break;
        case (uint32_t)GPIOB:
            switch (slt->pin_mosi) {
            case GPIO_PIN_7:
            case GPIO_PIN_11: af_mosi = GPIO_AF8_SPI2; break;
            case GPIO_PIN_15: af_mosi = GPIO_AF0_SPI2; break;
            default: return -1;
            }
            break;
        case (uint32_t)GPIOC:
            switch (slt->pin_mosi) {
            case GPIO_PIN_3: af_mosi = GPIO_AF1_SPI2; break;
            case GPIO_PIN_8: af_mosi = GPIO_AF8_SPI1; break;
            default: return -1;
            }
            break;
        default: return -1;
        }
        break;
    default: return -1;
    }

    gpio_ll_t gpio_cfg;
    if (config->clk_polarity == SPI_LL_CLK_POLARITY_LOW) {
        gpio_ll_init(&gpio_cfg, slt->port_sck, slt->pin_sck, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_DOWN, GPIO_LL_SPEED_VERY_HIGH, af_sck);
    } else {
        gpio_ll_init(&gpio_cfg, slt->port_sck, slt->pin_sck, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_UP, GPIO_LL_SPEED_VERY_HIGH, af_sck);
    }
    if (config->direction == SPI_LL_DIRECTION_2LINS_FULL_DUPLEX) {
        gpio_ll_init(&gpio_cfg, slt->port_miso, slt->pin_miso, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_UP, GPIO_LL_SPEED_VERY_HIGH, af_miso);
        gpio_ll_init(&gpio_cfg, slt->port_mosi, slt->pin_mosi, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_UP, GPIO_LL_SPEED_VERY_HIGH, af_mosi);
    } else if (config->direction == SPI_LL_DIRECTION_2LINS_RXONLY) {
        gpio_ll_init(&gpio_cfg, slt->port_miso, slt->pin_miso, GPIO_LL_MODE_AF, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_UP, GPIO_LL_SPEED_VERY_HIGH, af_miso);
    }
    if (slt->port_nss) {
        if (config->mode == SPI_LL_MODE_MASTER) {
            gpio_ll_init(&slt->gpio_nss, slt->port_nss, slt->pin_nss, GPIO_LL_MODE_OUTPUT, GPIO_LL_OTYPE_PP, GPIO_LL_PULL_NO, GPIO_LL_SPEED_MEDIUM, 0);
        } else {
            gpio_ll_init(&slt->gpio_nss, slt->port_nss, slt->pin_nss, GPIO_LL_MODE_INPUT, GPIO_LL_OTYPE_OD, GPIO_LL_PULL_DOWN, GPIO_LL_SPEED_MEDIUM, 0);
        }
    }
    
    uint32_t pclk = HAL_RCC_GetPCLK1Freq();
    float psc = (float)pclk / clk_freq;
    switch ((uint32_t)spi_handle->Instance) {
    case (uint32_t)SPI1: __HAL_RCC_SPI1_CLK_ENABLE(); break;
    case (uint32_t)SPI2: __HAL_RCC_SPI2_CLK_ENABLE(); break;
    default: return -1;
    }
    if (psc < 2) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
    } else if(psc < 4) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
    } else if(psc < 8) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
    } else if(psc < 16) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_16;
    } else if(psc < 32) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32;
    } else if(psc < 64) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_64;
    } else if(psc < 128) {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_128;
    } else {
        spi_handle->Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_256;
    }
    switch (config->direction) {
    case SPI_LL_DIRECTION_2LINS_FULL_DUPLEX: spi_handle->Init.Direction = SPI_DIRECTION_2LINES; break;
    case SPI_LL_DIRECTION_2LINS_RXONLY: spi_handle->Init.Direction = SPI_DIRECTION_2LINES_RXONLY; break;
    case SPI_LL_DIRECTION_1LINS_RX:
    case SPI_LL_DIRECTION_1LINS_TX: spi_handle->Init.Direction = SPI_DIRECTION_1LINE; break;
    default: return -1;
    }
    switch (config->clk_polarity) {
    case SPI_LL_CLK_POLARITY_LOW: spi_handle->Init.CLKPolarity = SPI_POLARITY_LOW; break;
    case SPI_LL_CLK_POLARITY_HIGH: spi_handle->Init.CLKPolarity = SPI_POLARITY_HIGH; break;
    default: return -1;
    }
    switch (config->phase) {
    case SPI_LL_PHASE_1EDGE: spi_handle->Init.CLKPhase = SPI_PHASE_1EDGE; break;
    case SPI_LL_PHASE_2EDGE: spi_handle->Init.CLKPhase = SPI_PHASE_2EDGE; break;
    default: return -1;
    }
    switch (config->datasize) {
    case SPI_LL_DATASIZE_8BIT: spi_handle->Init.DataSize = SPI_DATASIZE_8BIT; break;
    case SPI_LL_DATASIZE_16BIT: spi_handle->Init.DataSize = SPI_DATASIZE_16BIT; break;
    default: return -1;
    }
    switch (config->first_bit) {
    case SPI_LL_FIRST_BIT_MSB: spi_handle->Init.FirstBit = SPI_FIRSTBIT_MSB; break;
    case SPI_LL_FIRST_BIT_LSB: spi_handle->Init.FirstBit = SPI_FIRSTBIT_LSB; break;
    default: return -1;
    }
    spi_handle->Init.NSS = SPI_NSS_SOFT;
    switch (config->first_bit) {
    case SPI_LL_MODE_MASTER: spi_handle->Init.Mode = SPI_MODE_MASTER; break;
    case SPI_LL_MODE_SLAVE: spi_handle->Init.Mode = SPI_MODE_SLAVE; break;
    default: return -1;
    }
    if (config->crc_polynomial == 0) {
        spi_handle->Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    } else {
        spi_handle->Init.CRCCalculation = SPI_CRCCALCULATION_ENABLE;
        spi_handle->Init.CRCPolynomial = config->crc_polynomial;
    }
    HAL_SPI_DeInit(spi_handle);
    HAL_SPI_Init(spi_handle);
    __HAL_SPI_ENABLE(spi_handle);
    // switch ((uint32_t)spi_handle->Instance) {
    // case (uint32_t)SPI1:
    //     NVIC_SetPriority(SPI1_IRQn, slt->cfg_interrupt_priority);
    //     NVIC_EnableIRQ(SPI1_IRQn);
    //     break;
    // case (uint32_t)SPI2:
    //     NVIC_SetPriority(SPI2_IRQn, slt->cfg_interrupt_priority);
    //     NVIC_EnableIRQ(SPI2_IRQn);
    //     break;
    // }

    return 0;
    // clang-format on
#endif
    return -1;
}



/* [] END OF FILE */
